package dungeon;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import dungeonElements.NormalSquare;
import dungeonElements.TeleportationSquare;
import dungeonTools.Coordinate;
import dungeonTools.Direction;

/**
 * @author Tom Jacobs & Ewoud De Moor
 * @version 3.0
 */
public class ShaftTest {

	public static Shaft<TeleportationSquare> shaft;
	
	@Before
	public void setUp() throws Exception {
		shaft = new Shaft<TeleportationSquare>(Direction.WEST, 50);
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testNewShaft_valid() {
		for(Direction direction: Direction.values()){
			Shaft<TeleportationSquare> newShaft = new Shaft<TeleportationSquare>(direction, 50);
			if(direction==Direction.EAST||direction==Direction.WEST){
				assertEquals(50,newShaft.getXSize());
				assertEquals(1,newShaft.getYSize());
				assertEquals(1,newShaft.getZSize());
			}
			if(direction==Direction.NORTH||direction==Direction.SOUTH){
				assertEquals(1,newShaft.getXSize());
				assertEquals(50,newShaft.getYSize());
				assertEquals(1,newShaft.getZSize());
			}
			if(direction==Direction.CEILING||direction==Direction.FLOOR){
				assertEquals(1,newShaft.getXSize());
				assertEquals(1,newShaft.getYSize());
				assertEquals(50,newShaft.getZSize());
			}
		}
	}
	
	@Test 
	public void testSetXSize_valid(){
		assertEquals(50, shaft.getXSize());
		shaft.setXSize(51);
		assertEquals(51, shaft.getXSize());
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void testSetXSize_exception(){
		Shaft<TeleportationSquare> newShaft = new Shaft<TeleportationSquare>(Direction.CEILING, 50);
		newShaft.setXSize(2);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void testSetYSize_exception(){
		shaft.setYSize(2);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void testSetZSize_exception(){
		shaft.setZSize(2);
	}
	
	@Test
	public void testCanHaveAsSize_valid(){
		assertTrue(shaft.canHaveAsSize(50, 1, 1));
		assertTrue(shaft.canHaveAsSize(51, 1, 1));
		assertTrue(shaft.canHaveAsSize(Long.MAX_VALUE, 1, 1));
	}
	
	@Test
	public void testCanHaveAsSize_invalidSize(){
		assertFalse(shaft.canHaveAsSize(49, 1, 1));
		assertFalse(shaft.canHaveAsSize(51, 0, 1));
		assertFalse(shaft.canHaveAsSize(51, 1, -1));
		assertFalse(shaft.canHaveAsSize(51, 2, 1));
		assertFalse(shaft.canHaveAsSize(51, 1, 3));
	}
	
	@Test 
	public void testCanHaveAsSize_doorAtEnd(){
		assertTrue(shaft.canHaveAsSize(51, 1, 1));
		assertTrue(shaft.canHaveAsSize(50, 1, 1));
		assertFalse(shaft.canHaveAsSize(49, 1, 1));
		TeleportationSquare square = new NormalSquare();
		square.buildDoor(Direction.EAST);
		Coordinate coordinate = new Coordinate(49, 0, 0);
		assertTrue(shaft.canHaveSquareAtCoordinate(square, coordinate));
		shaft.addSquare(square , coordinate);
		assertTrue(shaft.contains(coordinate));
		assertTrue(shaft.contains(square));
		assertEquals(square, shaft.getSquareAtCoordinate(coordinate));
		assertFalse(shaft.canHaveAsSize(51, 1, 1));
		assertTrue(shaft.canHaveAsSize(50, 1, 1));
		assertFalse(shaft.canHaveAsSize(49, 1, 1));
	}
	
	@Test 
	public void testCanHaveAsSize_doorAtEndInOtherDirections(){
		assertTrue(shaft.canHaveAsSize(51, 1, 1));
		assertTrue(shaft.canHaveAsSize(50, 1, 1));
		assertFalse(shaft.canHaveAsSize(49, 1, 1));
		TeleportationSquare square = new NormalSquare();
		square.buildDoor(Direction.NORTH);
		square.buildDoor(Direction.SOUTH);
		square.buildDoor(Direction.CEILING);
		Coordinate coordinate = new Coordinate(49, 0, 0);
		assertTrue(shaft.canHaveSquareAtCoordinate(square, coordinate));
		shaft.addSquare(square , coordinate);
		assertTrue(shaft.contains(coordinate));
		assertTrue(shaft.contains(square));
		assertEquals(square, shaft.getSquareAtCoordinate(coordinate));
		assertTrue(shaft.canHaveAsSize(51, 1, 1));
		assertTrue(shaft.canHaveAsSize(50, 1, 1));
		assertFalse(shaft.canHaveAsSize(49, 1, 1));
	}
	
	@Test 
	public void testBuildDoorsInShaft_valid(){
		TeleportationSquare square = new NormalSquare();
		TeleportationSquare square2 = new NormalSquare();
		Coordinate coordinate = new Coordinate(48, 0, 0);
		Coordinate coordinate2 = new Coordinate(49, 0, 0);
		assertTrue(shaft.canHaveSquareAtCoordinate(square, coordinate));
		assertTrue(shaft.canHaveSquareAtCoordinate(square2, coordinate2));
		shaft.addSquare(square, coordinate);
		shaft.addSquare(square2, coordinate2);		
		assertTrue(shaft.contains(square));
		assertTrue(shaft.contains(square2));
		assertTrue(shaft.contains(coordinate));
		assertTrue(shaft.contains(coordinate2));
		assertEquals(square, shaft.getSquareAtCoordinate(coordinate));
		assertEquals(square2, shaft.getSquareAtCoordinate(coordinate2));
		square.buildDoor(Direction.NORTH);
		square.buildDoor(Direction.SOUTH);
		square.buildDoor(Direction.CEILING);
		square2.buildDoor(Direction.EAST);
		square2.buildDoor(Direction.NORTH);
		square2.buildDoor(Direction.SOUTH);
		assertTrue(square.hasProperBorders());
		assertTrue(square2.hasProperBorders());
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void testBuildDoorBetweenSquaresInShaftExeption(){
		TeleportationSquare square = new NormalSquare();
		TeleportationSquare square2 = new NormalSquare();
		Coordinate coordinate = new Coordinate(10, 0, 0);
		Coordinate coordinate2 = new Coordinate(11, 0, 0);
		assertTrue(shaft.canHaveSquareAtCoordinate(square, coordinate));
		assertTrue(shaft.canHaveSquareAtCoordinate(square2, coordinate2));
		shaft.addSquare(square, coordinate);
		shaft.addSquare(square2, coordinate2);
		assertTrue(shaft.contains(square));
		assertTrue(shaft.contains(square2));
		assertTrue(shaft.contains(coordinate));
		assertTrue(shaft.contains(coordinate2));
		assertEquals(square, shaft.getSquareAtCoordinate(coordinate));
		assertEquals(square2, shaft.getSquareAtCoordinate(coordinate2));
		square.buildDoor(Direction.EAST);
	}
	
	@Test
	public void testCanHaveSquareAtCoordinate_validDoorAtOrigin(){
		for(Direction direction: Direction.values()){
			if( (direction!=Direction.EAST) && (direction!=Direction.FLOOR) ){
				TeleportationSquare square = new NormalSquare();
				square.buildDoor(direction);
				assertFalse(shaft.canHaveSquareAtCoordinate(square, Coordinate.ORIGIN));
			}
		}
	}
	
	@Test
	public void testCanHaveSquareAtCoordinate_invalidDoorAtOrigin(){
		TeleportationSquare square = new NormalSquare();
		square.buildDoor(Direction.EAST);
		assertFalse(shaft.canHaveSquareAtCoordinate(square, Coordinate.ORIGIN));
	}
	
	@Test
	public void testCanHaveSquareAtCoordinate_validDoorAtEnd(){
		Coordinate coordinate = new Coordinate(49, 0, 0);
		for(Direction direction: Direction.values()){
			if( (direction!=Direction.WEST) && (direction!=Direction.FLOOR) ){
				TeleportationSquare square = new NormalSquare();
				square.buildDoor(direction);
				assertTrue(shaft.canHaveSquareAtCoordinate(square, coordinate));
			}
		}
	}
	
	@Test
	public void testCanHaveSquareAtCoordinate_invalidDoorAtEnd(){
		Coordinate coordinate = new Coordinate(49, 0, 0);
		TeleportationSquare square = new NormalSquare();
		square.buildDoor(Direction.WEST);
		assertFalse(shaft.canHaveSquareAtCoordinate(square, coordinate));
	}
	
	@Test
	public void testCanHaveSquareAtCoordinate_validDoor(){
		Coordinate coordinate = new Coordinate(25, 0, 0);
		for(Direction direction: Direction.values()){
			if( (direction!=Direction.WEST) && (direction!=Direction.EAST) && (direction!=Direction.FLOOR) ){
				TeleportationSquare square = new NormalSquare();
				square.buildDoor(direction);
				assertTrue(shaft.canHaveSquareAtCoordinate(square, coordinate));
			}
		}
	}
	
	@Test
	public void testCanHaveSquareAtCoordinate_invalidDoorEast(){
		Coordinate coordinate = new Coordinate(25, 0, 0);
		TeleportationSquare square = new NormalSquare();
		square.buildDoor(Direction.EAST);
		assertFalse(shaft.canHaveSquareAtCoordinate(square, coordinate));
	}
	
	@Test
	public void testCanHaveSquareAtCoordinate_invalidDoorWest(){
		Coordinate coordinate = new Coordinate(25, 0, 0);
		TeleportationSquare square = new NormalSquare();
		square.buildDoor(Direction.WEST);
		assertFalse(shaft.canHaveSquareAtCoordinate(square, coordinate));
	}
	
}
